package cn.school.sys.service.impl;


import cn.school.common.utils.JwtTokenUtil;
import cn.school.common.utils.StringUtils;
import cn.school.common.utils.SysUserUtils;
import cn.school.common.constant.CommonConstant;
import cn.school.sys.dao.SysDeptDao;
import cn.school.sys.dao.SysUserDao;
import cn.school.sys.entity.*;
import cn.school.sys.service.OnlineUserService;
import cn.school.sys.service.SysUserRoleService;
import cn.school.sys.service.SysUserService;
import cn.hutool.core.util.StrUtil;
import cn.school.sys.vo.LoginInfoVo;
import cn.school.sys.vo.SysUserTeacherImportVo;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 后台用户表
 */
@Slf4j
@Service("sysUserService")
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {

    @Resource
    private UserDetailsService userDetailsService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private OnlineUserService onlineUserService;
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private SysDeptDao sysDeptDao;


    @Override
    public SysUser getByUserName(String username,boolean isAll) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>();
        wrapper.eq(SysUser::getUsername, username);
        if(!isAll){
            wrapper.eq(SysUser::getStatus,1);
            SysUser sysUser = this.baseMapper.selectOne(wrapper);
            if(sysUser != null){
                LambdaQueryWrapper<SysDept> deptWrapper = new LambdaQueryWrapper<>();
                deptWrapper.eq(SysDept::getStatus,"1");
                deptWrapper.eq(SysDept::getId,sysUser.getDeptId());
                int count = sysDeptDao.selectCount(deptWrapper);
                if(count==0){
                    return null;
                }
            }
        }

        return this.baseMapper.selectOne(wrapper);
    }

    @Override
    public String login(String username, String password, HttpServletRequest request) {
        String token = null;
        //密码需要客户端加密后传递
        try {
            SysUser user = this.getByUserName(username,false);
            if(user==null){
                throw new BadCredentialsException("用户不存在");
            }
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails.getUsername());

            SysUser sysUser = SysUserUtils.getSysUser();
            // 保存在线信息
            onlineUserService.save(sysUser, token, jwtTokenUtil.getExpiration(), request);

            boolean singleLogin = false;

            if (singleLogin) {
                //踢掉之前已经登录的token
                onlineUserService.checkLoginOnUser(sysUser.getUsername(), token);
            }
        } catch (AuthenticationException e) {
            log.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }

    @Override
    public String refreshToken(String oldToken) {
        String token = oldToken.substring(jwtTokenUtil.getTokenHead().length());
        if (jwtTokenUtil.canRefresh(token)) {
            return jwtTokenUtil.refreshToken(token);
        }
        return null;
    }

    @Override
    public SysUser getUserById(Long id) {
        return getById(id);
    }


    @Override
    public int update(Long id, SysUser user) {
        user.setId(id);
        return this.baseMapper.updateById(user);
    }

    @Override
    public int delete(Long id) {
        return this.baseMapper.deleteById(id);
    }

    @Override
//    @DataScope(userId = "id")
    public IPage<SysUser> getPage(Map<String, Object> params) {
        int pageSize = Integer.parseInt(String.valueOf(params.get("pageSize")));
        int pageNum = Integer.parseInt(String.valueOf(params.get("pageNum")));

        String sysuName = (String) params.get("sysuName");
        String phone = (String) params.get("phone");
        String deptId = (String) params.get("deptId");
        String beginTime = (String) params.get("beginTime");
        String endTime = (String) params.get("endTime");
        String status = (String) params.get("status");
        String syroId = (String) params.get("syroId");

        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();

        if (StrUtil.isNotEmpty(sysuName)) {
            wrapper.like("syus.sysu_name", sysuName);
        }
        if (StrUtil.isNotEmpty(phone)) {
            wrapper.like("syus.phone", phone);
        }
        if (StrUtil.isNotEmpty(deptId)) {
//            wrapper.apply("(syus.dept_id = " + deptId + " OR dept_id IN ( SELECT t.id FROM t_sys_dept t WHERE FIND_IN_SET ( " + deptId + " , ancestors ) ))");
            wrapper.apply("syus.dept_id = " + deptId );
        }
        if (StrUtil.isNotEmpty(beginTime)) {
            wrapper.gt("syus.create_time", beginTime).or().eq("syus.create_time", beginTime);
        }

        if (StrUtil.isNotEmpty(endTime)) {
            wrapper.lt("syus.create_time", endTime).or().eq("syus.create_time", endTime);
        }
        if (StrUtil.isNotEmpty(status)) {
            wrapper.eq("syus.status", status);
        }

        if (StrUtil.isNotEmpty(syroId)) {
            wrapper.eq("syro.id", syroId);
        }
        wrapper.eq("syus.tenant_id",SysUserUtils.getSysUser().getTenantId());
//      wrapper.orderByAsc("syro.id");

//        wrapper.apply(params.get(CommonConstant.SQL_FILTER) != null, (String) params.get(CommonConstant.SQL_FILTER));
        wrapper.orderByDesc("syus.create_time");

        Page<SysUser> page = new Page();
        page.setSize(pageSize);
        page.setCurrent(pageNum);
        System.out.println(SysUserUtils.getSysUser().getTenantId());
        List<SysUser> list = this.baseMapper.getPage(page, wrapper);
        if (list != null && list.size() != 0) {
            // 用户ID列表
            List idList = list.stream().map(SysUser::getId).collect(Collectors.toList());
            // 获取所有用户的角色列表;
            List<SysUserRole> roleList = this.sysUserRoleService.listRoleByUserListId(idList);
            // 用户角色列表：进行分组：key userId
            Map<Long, List<SysUserRole>> roleMap = roleList.stream().collect(Collectors.groupingBy(SysUserRole::getUserId));
            for (SysUser sysUser : list) {
                if (roleMap.containsKey(sysUser.getId())) {
                    List<SysUserRole> tempUserRoleList = roleMap.get(sysUser.getId());
                    if (tempUserRoleList != null && tempUserRoleList.size() != 0) {
                        List<SysRole> tempRoleList = tempUserRoleList.stream()
                                .map(e -> new SysRole(e.getRoleId(), e.getRoleName()))
                                .collect(Collectors.toList());
                        sysUser.setRoleList(tempRoleList);
                    }
                }
            }
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public int updateUserAndRole(SysUser user, Long roleId) {
        if (StrUtil.isNotEmpty(user.getSysuHiredate())) {
            user.setSysuHiredate(user.getSysuHiredate().substring(0,10));
        }
        if (StrUtil.isNotEmpty(user.getSysuLeavedate())) {
            user.setSysuLeavedate(user.getSysuLeavedate().substring(0,10));
        }

        //先删除用户与角色关系
        if (roleId == null) {
            // 不是特殊角色（班主任、教师）才做角色的更新
            sysUserRoleService.delAndCreateRole(user.getId(), user.getRoleIds());
        }
        // 更新用户
        return this.baseMapper.updateById(user);
    }

    @Override
    public int updatePasswordByUserId(Long userId, String newPassword) {
        SysUser user = new SysUser();
        user.setPassword(newPassword);
        user.setId(userId);
        return this.baseMapper.updateById(user);
    }

    @Override
    public int updateStatus(Long id, String status) {
        SysUser user = new SysUser();
        user.setId(id);
        user.setStatus(status);
        return this.baseMapper.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUserAndRole(SysUser user, Long roleId) {
        String tenantId = StringUtils.isNotEmpty(user.getTenantId()) ? user.getTenantId() : SysUserUtils.getSysUser().getTenantId();

        if (StrUtil.isNotEmpty(user.getSysuHiredate())) {
            user.setSysuHiredate(user.getSysuHiredate().substring(0,10));
        }
        if (StrUtil.isNotEmpty(user.getSysuLeavedate())) {
            user.setSysuLeavedate(user.getSysuLeavedate().substring(0,10));
        }
        user.setTenantId(tenantId);
        int result = this.baseMapper.insert(user);
        //保存用户与角色关系
        List<Long> roleIds = null;
        if (roleId != null) {
            roleIds = new ArrayList<>();
            roleIds.add(roleId);
        } else {
            roleIds = user.getRoleIds();
        }
        sysUserRoleService.insertUserAndUserRole(user.getId(), roleIds, tenantId);
        return result;
    }

    @Override
    public int deleteByIds(Long[] ids) {
        return this.baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

    @Override
    public List<SysUser> getExportList(Map<String, Object> params) {

        String username = (String) params.get("username");
        String phone = (String) params.get("phone");
        String deptId = (String) params.get("deptId");
        String beginTime = (String) params.get("beginTime");
        String endTime = (String) params.get("endTime");
        String status = (String) params.get("status");

        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(username)) {
            wrapper.like(SysUser::getUsername, username);
        }
        if (StrUtil.isNotEmpty(phone)) {
            wrapper.like(SysUser::getPhone, phone);
        }
        if (StrUtil.isNotEmpty(deptId)) {
            wrapper.apply("(dept_id = " + deptId + " OR dept_id IN ( SELECT t.id FROM t_sys_dept t WHERE FIND_IN_SET ( " + deptId + " , ancestors ) ))");
        }
        if (StrUtil.isNotEmpty(beginTime)) {
            wrapper.gt(SysUser::getCreateTime, beginTime);
        }

        if (StrUtil.isNotEmpty(endTime)) {
            wrapper.lt(SysUser::getCreateTime, endTime);
        }
        if (StrUtil.isNotEmpty(status)) {
            wrapper.eq(SysUser::getStatus, status);
        }
        //租户
        wrapper.eq(SysUser::getTenantId, SysUserUtils.getSysUser().getTenantId());
        wrapper.apply(params.get(CommonConstant.SQL_FILTER) != null, (String) params.get(CommonConstant.SQL_FILTER));
        return list(wrapper);
    }

    @Override
    public List<SysUser> getExportListByRole(Map<String, Object> params) {
       params.put("pageSize", "1000000");
       params.put("pageNum", "1");
       IPage<SysUser> page =  this.getPage(params);
       return page.getRecords();
    }

    @Override
    public List<SysUser> getListAll() {
        return list(new LambdaQueryWrapper<SysUser>());
    }

    @Override
    public List<SysUser> getClassTeacherList() {
        return sysUserDao.getClassTeacherList(SysUserUtils.getSysUser().getTenantId());
    }

    @Override
    public List<SysUser> getDorTeacherList() {
        return sysUserDao.getDorTeacherList();
    }

    @Override
    public String getLoginRoleNames(String username) {
        LoginInfoVo loginInfoVo=sysUserDao.getLoginInfo(username);
        return loginInfoVo.getRoleName();
    }

    @Override
    public IPage<SysUser> getUserPage(Map<String, Object> params) {
        int pageSize = Integer.parseInt(String.valueOf(params.get("pageSize")));
        int pageNum = Integer.parseInt(String.valueOf(params.get("pageNum")));

        String username = (String) params.get("username");

        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.select("id", "username","dept_name");
        wrapper.eq("status",1);
        if (StrUtil.isNotEmpty(username)) {
            wrapper.like("userName", username);
        }

        wrapper.apply(params.get(CommonConstant.SQL_FILTER) != null, (String) params.get(CommonConstant.SQL_FILTER));
        return page(new Page<>(pageNum, pageSize), wrapper);
    }

    @Override
    public IPage<SysUser> getPersonnelMangerPage(Map<String, Object> params) {
        int pageSize = Integer.parseInt(String.valueOf(params.get("pageSize")));
        int pageNum = Integer.parseInt(String.valueOf(params.get("pageNum")));

        String username = (String) params.get("username");
        String phone = (String) params.get("phone");
        String deptId = (String) params.get("deptId");
        String beginTime = (String) params.get("beginTime");
        String endTime = (String) params.get("endTime");
        String status = (String) params.get("status");
        String syroId = (String) params.get("syroId");

        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();

        if (StrUtil.isNotEmpty(username)) {
            wrapper.like("syus.username", username);
        }
        if (StrUtil.isNotEmpty(phone)) {
            wrapper.like("syus.phone", phone);
        }
        if (StrUtil.isNotEmpty(beginTime)) {
            wrapper.gt("syus.create_time", beginTime);
        }

        if (StrUtil.isNotEmpty(endTime)) {
            wrapper.lt("syus.create_time", endTime);
        }
        if (StrUtil.isNotEmpty(status)) {
            wrapper.eq("syus.status", status);
        }

        if (StrUtil.isNotEmpty(syroId)) {
            wrapper.eq("syro.id", syroId);
        }
        wrapper.eq("syus.tenant_id",SysUserUtils.getSysUser().getTenantId());
        Page<SysUser> page = new Page();
        page.setSize(pageSize);
        page.setCurrent(pageNum);
        List<SysUser> list = this.baseMapper.getPage(page, wrapper);
        page.setRecords(list);
        return page;
    }

    @Override
    public void importTeacherUser(InputStream inputStream, Class<SysUserTeacherImportVo> sysUserTeacherImportVoClass, TeacherImportListener teacherImportListener) {
        //easyexcel导入文件
        EasyExcel.read(inputStream, SysUserTeacherImportVo.class, teacherImportListener).sheet().doRead();
    }

    @Override
    public void insertUserRoleRalation(Long userId, Long roleId) {
        LambdaQueryWrapper<SysUserRole> delQuery = new LambdaQueryWrapper<>();
        delQuery.eq(SysUserRole::getUserId, userId);
        delQuery.eq(SysUserRole::getRoleId, roleId);
        this.sysUserRoleService.remove(delQuery);
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(userId);
        sysUserRole.setRoleId(roleId);
        this.sysUserRoleService.save(sysUserRole);
    }

    @Override
    public void importHeadMasterUser(InputStream inputStream, Class<SysUserTeacherImportVo> sysUserTeacherImportVoClass, HeadMasterImportListener headMasterImportListener) {
        //easyexcel导入文件
        EasyExcel.read(inputStream, SysUserTeacherImportVo.class, headMasterImportListener).sheet().doRead();
    }

    @Override
    public List<SysUser> getAllTeacherList() {
        return sysUserDao.getClassTeacherList(SysUserUtils.getSysUser().getTenantId());
    }

    @Override
    public IPage<SysUser> getUserList(SysUser user) {
        user.setTenantId(SysUserUtils.getSysUser().getTenantId());
        int count = sysUserDao.userPhoneListCount(user);
        int startNum = (user.getPageNum() - 1) * user.getPageSize();
        List<SysUser> list = sysUserDao.userPhoneList(user,startNum,user.getPageSize());
        Page<SysUser> page = new Page<>();
        page.setTotal(count);
        page.setRecords(list);
        return page;
    }
}
